﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Linq.Expressions;
using System.Reflection;

namespace SL8.SL
{
    /// <summary>
    /// 视图模型基类扩展
    /// </summary>
    public static class ObservableObjectExtension
    {
        public static void SetValue<T, TProperty>(this T viewModel, Expression<Func<T, TProperty>> expression, object value)
          where T : ObservableObject
        {
            string propertyName = viewModel.GetPropertyName(expression);
            Type viewModelType = viewModel.GetType();

            PropertyInfo propertyInfo = viewModelType.GetProperty(propertyName);

            if (propertyInfo != null)
            {
                propertyInfo.SetValue(viewModel, value, null);
                viewModel.RaisePropertyChanged(propertyName);
            }
        }

        public static void SetCacheValue<T, TProperty>(this T viewModel, Expression<Func<T, TProperty>> expression, object value)
                 where T : ObservableObject
        {
            string propertyName = viewModel.GetPropertyName(expression);
            viewModel.SetCacheValue(propertyName, value);
        }

        public static void SetCacheValueAndValidate<T, TProperty>(this T viewModel, Expression<Func<T, TProperty>> expression, object value)
                 where T : ObservableObject
        {
            string propertyName = viewModel.GetPropertyName(expression);
            viewModel.ValidateProperty(viewModel.GetPropertyName(expression), value);
            viewModel.SetCacheValue(propertyName, value);
            viewModel.RaisePropertyChanged(viewModel.GetPropertyName(expression));
        }

        #region 获取值扩展 此处不用默认参数值是为了代码编写是自动提示
        public static TReturnValue GetCacheValue<T, TProperty, TReturnValue>(this T viewModel, Expression<Func<T, TProperty>> expression, TReturnValue defaultValue, bool setAsInit)
                 where T : ObservableObject
        {
            string propertyName = viewModel.GetPropertyName(expression);
            return viewModel.GetCacheValue(propertyName, defaultValue, setAsInit);
        }

        public static TReturnValue GetCacheValue<T, TProperty, TReturnValue>(this T viewModel, Expression<Func<T, TProperty>> expression, TReturnValue defaultValue)
                where T : ObservableObject
        {
            return viewModel.GetCacheValue(expression, defaultValue, true);
        }

        public static TReturnValue GetCacheValue<T, TProperty, TReturnValue>(this T viewModel, Expression<Func<T, TProperty>> expression, Func<TReturnValue> funcDefaultValue, bool setAsInit)
                where T : ObservableObject
        {
            if (funcDefaultValue == null)
            {
                throw new ArgumentNullException("funcDefaultValue");
            }

            string propertyName = viewModel.GetPropertyName(expression);
            return viewModel.GetCacheValue(propertyName, funcDefaultValue, setAsInit);
        }

        public static TReturnValue GetCacheValue<T, TProperty, TReturnValue>(this T viewModel, Expression<Func<T, TProperty>> expression, Func<TReturnValue> funcDefaultValue) where T : ObservableObject
        {
            return viewModel.GetCacheValue(expression, funcDefaultValue, true);
        }
        #endregion

        public static string GetPropertyName<T, TProperty>(this T owner, Expression<Func<T, TProperty>> expression) where T : ObservableObject
        {
            var memberExpression = expression.Body as MemberExpression;
            if (memberExpression == null)
            {
                var unaryExpression = expression.Body as UnaryExpression;
                if (unaryExpression != null)
                {
                    memberExpression = unaryExpression.Operand as MemberExpression;
                    if (memberExpression == null)
                    {
                        throw new NotImplementedException();
                    }
                }
                else
                {
                    throw new NotImplementedException();
                }
            }

            var propertyName = memberExpression.Member.Name;
            return propertyName;
        }

        public static void RaisePropertyChanged<T, TProperty>(this T viewModel, Expression<Func<T, TProperty>> expression) where T : ObservableObject
        {
            viewModel.RaisePropertyChanged(viewModel.GetPropertyName(expression));
        }

        public static void ValidateProperty<T, TProperty>(this T viewModel, Expression<Func<T, TProperty>> expression, object value) where T : ObservableObject
        {
            viewModel.ValidateProperty(viewModel.GetPropertyName(expression), value);
        }
    }
}
